--UIIndicator
--create by zouyb
--页面高度指示器

--使用方法：在scrollview初始化完毕后，调用代码：UIIndicator.attach(scrollview);

--UIIndicator继承自Widget
UIIndicator = class("UIIndicator", function()
    return ccui.Widget:create();
end);

-- 在scrollview上附加高度指示器
function UIIndicator.attach(scrollview, indicatorResident, pageCallback)
    return UIIndicator.new(scrollview, indicatorResident, pageCallback);
end

-- 构造函数
-- @param scrollview 滚动容器
-- @param indicatorResident 指示器是否常驻（默认为不常驻）
-- @param pageCallback 滚动到底部时的回调
function UIIndicator:ctor(scrollview, indicatorResident, pageCallback)
    self.scrollview = scrollview;
    self.indicatorResident = indicatorResident or false;
    self.pageCallback = pageCallback;

    --初始化
    local node = cc.CSLoader:createNode("layout/common/Indicator.csb");
    node:setAnchorPoint(cc.p(0, 0));
    self:setName("UIIndicator");
    self:addChild(node);
    self.node = node;

    local anchorPoint = scrollview:getAnchorPoint();
    local scroviewSize = scrollview:getContentSize();
    local relativePos = cc.p((1-anchorPoint.x) * scroviewSize.width, -anchorPoint.y * scroviewSize.height + 1);
    local scrollviewPos = cc.p(scrollview:getPosition());
    self:setPosition(cc.pAdd(scrollviewPos, relativePos));

    scrollview:getParent():addChild(self);

    local indicatorNode = findChildByName(node, "node");

    -- 如果指示器需要常驻
    local needShow = self:needShow(scrollview);
    if self.indicatorResident or needShow then
        indicatorNode:setOpacity(255);
    else
        indicatorNode:setOpacity(0);
    end
    local function eventListener(sender, eventType)
        if eventType == ccui.ScrollviewEventType.scrolling then

            if not needShow then
                return;
            end

             -- 如果指示器不常驻，定时隐藏
            if not self.indicatorResident then
                indicatorNode:setOpacity(255);
                self:stopAllActions();
                local function hide()
                    indicatorNode:runAction(cc.FadeOut:create(1));
                end
                performWithDelay(self, hide, 1);
            end

        elseif eventType == ccui.ScrollviewEventType.scrollToBottom then
            if self.pageCallback then
                self.pageCallback();
            end
        end
    end
    ScrollTool.addEventListener(scrollview, eventListener);

    local function update(delta)
        if indicatorNode.isMoving then
            -- 指示器正在拖动，不处理
            return;
        end

        -- 视口高度
        local viewportHeight = self.scrollview:getContentSize().height;

        -- 总高度
        local totalHeight = self.scrollview:getInnerContainerSize().height;

        -- 指示器高度
        local indicatorNodeHeight = (viewportHeight / totalHeight) * viewportHeight;
        if indicatorNodeHeight < indicatorNode:getContentSize().height then
            indicatorNodeHeight = indicatorNode:getContentSize().height;
        end

        indicatorNode:setContentSize(indicatorNode:getContentSize().width, indicatorNodeHeight);

        -- 当前位置
        local scrollContainerPosY = self.scrollview:getInnerContainer():getPositionY();
        local indicatorPosY = - scrollContainerPosY / totalHeight * viewportHeight;

        local minY = 0;
        local maxY = viewportHeight - indicatorNodeHeight;

        indicatorPosY = iif(indicatorPosY < minY, 0, indicatorPosY);
        indicatorPosY = iif(indicatorPosY > maxY, maxY, indicatorPosY);

        indicatorNode:setPositionY(indicatorPosY);
    end
    self:scheduleUpdateWithPriorityLua(update, 0)

    -- 初始化指示器在滑动过程中已经移动的高度
    indicatorNode.lastDeltaY = 0;

    -- 注册指示器拖动事件
    local function onIndicatorMove(sender, eventType)
        if eventType == ccui.TouchEventType.moved then
            -- 标记正在拖动中
            indicatorNode.isMoving = true;

            local movePos = sender:getTouchMovePosition();
            local beganPos =  sender:getTouchBeganPosition();

            -- 开始拖动后，指示器要一直显示
            self:stopAllActions();

            local deltaY =  movePos.y - beganPos.y;
            local curMoveY = deltaY - indicatorNode.lastDeltaY;
            indicatorNode.lastDeltaY = deltaY;

            -- 视口高度
            local viewportHeight = self.scrollview:getContentSize().height;

            -- 总高度
            local totalHeight = self.scrollview:getInnerContainerSize().height;

            -- 指示器高度
            local indicatorNodeHeight = (viewportHeight / totalHeight) * viewportHeight;
            if indicatorNodeHeight < indicatorNode:getContentSize().height then
                indicatorNodeHeight = indicatorNode:getContentSize().height;
            end

            local indicatorPosY = indicatorNode:getPositionY() + curMoveY;

            local minY = 0;
            local maxY = viewportHeight - indicatorNodeHeight;

            indicatorPosY = iif(indicatorPosY < minY, 0, indicatorPosY);
            indicatorPosY = iif(indicatorPosY > maxY, maxY, indicatorPosY);

            -- 更新指示器的坐标
            indicatorNode:setPositionY(indicatorPosY);

            -- 根据指示器的坐标计算滚动容器滚动的位置
            local percent = 100 *  indicatorPosY / maxY;

            self.scrollview:jumpToPercentVertical(percent);

            -- 到底部了
            if percent == 0 then
                if self.pageCallback then
                    self.pageCallback(true);
                end
            -- 到顶部了
            elseif percent == 100 then
                if self.pageCallback then
                    self.pageCallback(false);
                end
            end

        elseif eventType == ccui.TouchEventType.canceled then
            -- 取消拖动标记
            indicatorNode.isMoving = false;
            indicatorNode.lastDeltaY = 0;
            performWithDelay(indicatorNode, function() indicatorNode.isMoving = false; end, 0.3);

        elseif eventType == ccui.TouchEventType.ended then
            -- 取消拖动标记
            indicatorNode.isMoving = false;
            indicatorNode.lastDeltaY = 0;
        end
    end
    indicatorNode:setTouchEnabled(true);
    indicatorNode:addTouchEventListener(onIndicatorMove);
end

-- 是否需要显示
function UIIndicator:needShow(scrollview)
    local contentHeight = scrollview:getContentSize().height;
    local containerHeight = scrollview:getInnerContainerSize().height;

    if containerHeight <= contentHeight then
        return false;
    end

    return true;
end
